package io.kiki.stack.http.feign.hystrix;

import com.netflix.hystrix.HystrixCommand;
import feign.Capability;
import feign.Contract;
import feign.InvocationHandlerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * Allows Feign interfaces to return HystrixCommand or rx.Observable or rx.Single objects. Also
 * decorates normal Feign methods with circuit breakers, but calls {@link HystrixCommand#execute()}
 * directly.
 */
public final class HystrixCapability implements Capability {

    private final Map<Class, Object> fallbacks = new HashMap<>();
    private SetterFactory setterFactory = new SetterFactory.Default();

    /**
     * Allows you to override hystrix properties such as thread pools and command keys.
     */
    public HystrixCapability setterFactory(SetterFactory setterFactory) {
        this.setterFactory = setterFactory;
        return this;
    }

    @Override
    public Contract enrich(Contract contract) {
        return new HystrixDelegatingContract(contract);
    }

    @Override
    public InvocationHandlerFactory enrich(InvocationHandlerFactory invocationHandlerFactory) {
        return (target, dispatch) -> new HystrixInvocationHandler(target, dispatch, setterFactory, fallbacks.containsKey(target.type()) ? new FallbackFactory.Default<>(fallbacks.get(target.type())) : null);
    }

    public <E> Capability fallback(Class<E> api, E fallback) {
        fallbacks.put(api, fallback);

        return this;
    }
}
